﻿Imports System.ServiceModel
Imports System.ServiceModel.Configuration
Imports System.Configuration

<ServiceBehavior(InstanceContextMode:=InstanceContextMode.Single, ConcurrencyMode:=ConcurrencyMode.Single)>
Public Class NetNotification
    Implements INetNotification


    Private _type_map As New Dictionary(Of Type, IContentXml)

    Public Sub start()
        Dim group As ServiceModelSectionGroup = ServiceModelSectionGroup.GetSectionGroup(ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None))
        If group IsNot Nothing Then
            Dim service As ServiceElement = group.Services.Services(1)
            Dim baseAddress As String = service.Endpoints(0).Address.AbsoluteUri.Replace(service.Endpoints(0).Address.AbsolutePath, String.Empty)
            Dim host As New ServiceHost(Me, {New Uri(baseAddress)})
            host.AddServiceEndpoint(GetType(INetNotification), New NetTcpBinding("tcp"), service.Endpoints(0).Address.AbsolutePath)
            host.Open()
        End If
    End Sub

    Private _consumer As New HashSet(Of INetContentDispatcherConsumer)
    Private _lock As New Object

    Private cd As IContentDispatcher = getGlobalObject(Of IContentDispatcher)()

    Public Sub New()
        AddHandler cd.contentAdded, AddressOf Me.notificateAdd
        AddHandler cd.contentRemoved, AddressOf Me.notificateRemove
        AddHandler cd.contentEdit, AddressOf Me.notificateEdit

        For Each Type As Type In getMystery.AssemblyRegister.getTypesMarkedWith(Of ContentType)()
            Dim attr As ContentType = getMystery.AssemblyRegister.getMysteryClassAttribute(Of ContentType)(Type)
            _type_map(Type) = Type.getMysteryAttribute(Of ContentXmlAttr)().getXmler
        Next

    End Sub

    Public Function HelloWorld() As String Implements INetNotification.HelloWorld
        Return "hi there"
    End Function

    Private Sub notificateAdd(content As IContent)
        Dim message As New contentAddedInput With {.guid = content.guid.ToString}
        For Each c As INetContentDispatcherConsumer In getConsumers()
            c.contentAdded(message)
        Next
    End Sub

    Private Sub notificateRemove(content As IContent)
        Dim message As New contentRemovedInput With {.doc = _type_map(content.GetType()).generate(content).InnerXml}
        For Each c As INetContentDispatcherConsumer In getConsumers()
            c.contentRemoved(message)
        Next
    End Sub

    Private Sub notificateEdit(content As IContent)
        Dim message As New notificateEditInput With {.doc = _type_map(content.GetType()).generate(content).InnerXml}
        For Each c As INetContentDispatcherConsumer In getConsumers()
            c.contentEdit(message)
        Next
    End Sub

    Private Function getConsumers() As IEnumerable(Of INetContentDispatcherConsumer)
        SyncLock _lock
            Dim result As New HashSet(Of INetContentDispatcherConsumer)
            For Each c As INetContentDispatcherConsumer In _consumer
                Try
                    c.HelloWorld()
                    result.Add(c)
                Catch ex As Exception

                End Try
            Next
            _consumer = result
            Return result
        End SyncLock
    End Function

    Public Sub registerConsumer() Implements INetNotification.registerConsumer
        Dim callback As INetContentDispatcherConsumer = OperationContext.Current.GetCallbackChannel(Of INetContentDispatcherConsumer)()
        If callback IsNot Nothing Then
            SyncLock _lock
                _consumer.Add(callback)
            End SyncLock
        End If
    End Sub
End Class
